﻿using System;
using System.Data;
using System.Configuration;
using System.Linq;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Xml.Linq;
using System.Collections;

namespace Server.Utils.JSON
{
    public class JSONDecoder
    {
        JSONTokenizer m_tokenizer = null;
        JSONToken m_token = null;

        object m_value = null;

        public JSONDecoder(string str)
        {
            m_tokenizer = new JSONTokenizer(str);
            NextToken();
            m_value = ParseValue();
        }

        public JSONObject GetValue()
        {
            if (m_value.GetType() != typeof(JSONObject))
            {
                throw new JSONParseException(0, "Must Started by Object");
            }

            return (JSONObject)m_value;
        }

        private void NextToken()
        {
            m_token = m_tokenizer.GetNextToken();
        }

        private ArrayList ParseArray()
        {
            ArrayList arr = new ArrayList();

            NextToken();

            if (m_token.type == JSONTokenType.RIGHT_BRAKCET)
            {
                return arr;
            }

            while (true)
            {
                arr.Add(ParseValue());
                NextToken();

                if (m_token.type == JSONTokenType.RIGHT_BRAKCET)
                {
                    return arr;
                }
                else if (m_token.type == JSONTokenType.COMMA)
                {
                    NextToken();
                }
                else
                {
                    throw new JSONParseException(m_token.loc, "Expecting ']' or ',' buf found " + m_token.value.ToString());
                }
            }
        }

        private JSONObject ParseObject()
        {
            JSONObject obj = new JSONObject();
            string key = null;
            NextToken();

            if (m_token.type == JSONTokenType.RIGHT_BRACE)
            {
                return obj;
            }

            while (true)
            {
                if (m_token.type == JSONTokenType.STRING)
                {
                    key = (string)m_token.value;
                    NextToken();

                    if (m_token.type == JSONTokenType.COLON)
                    {
                        NextToken();
                        obj[key] = ParseValue();

                        NextToken();

                        if (m_token.type == JSONTokenType.RIGHT_BRACE)
                        {
                            return obj;
                        }
                        else if (m_token.type == JSONTokenType.COMMA)
                        {
                            NextToken();
                        }
                        else
                        {
                            throw new JSONParseException(m_token.loc, "Expecting '}' or ',', but found '" + m_token.value + "'");
                        }
                    }
                    else
                    {
                        throw new JSONParseException(m_token.loc, "Expecting ':' buf found " + m_token.value);
                    }
                }
                else
                {
                    throw new JSONParseException(m_token.loc, "Expecting string buf found " + m_token.value);
                }
            }
        }

        private object ParseValue()
        {
            switch (m_token.type)
            {
                case JSONTokenType.LEFT_BRACE:      //{
                    return ParseObject();
                case JSONTokenType.LEFT_BRACKET:    //[
                    return ParseArray();
                case JSONTokenType.STRING:
                case JSONTokenType.NUMBER:
                case JSONTokenType.BOOLEAN:
                case JSONTokenType.NULL:
                    return m_token.value;
                default:
                    throw new JSONParseException(m_token.loc, "Unexpected " + m_token.value);
            }
        }
    }
}